﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Alma.Models;
using System.Web.Helpers;
using System.IO;
using AlmaDatabase;
using System.Diagnostics;

public class ProductJoin
{
    public Product Product;
    public Shop Shop;
    public Section Section;
}

namespace Alma.Controllers
{
    public class ProductController : Controller
    {  
        public ActionResult IndexByShopId(int shopId, int page = 0, int productsPerPage = 100)
        {
            using (var context = new AlmaDBEntities())
            {

                var products = context.Products;
                var list = from product in products
                           join shop in context.Shops on product.ID_Shop equals shop.ID
                           join section in context.Sections on product.ID_Section equals section.ID
                           where product.ID_Shop == shopId
                           orderby product.ID
                           select new ProductJoin
                           {
                               Product = product,
                               Shop = shop,
                               Section = section
                           };
                ViewData["shopId"] = shopId;
                return View("Index", list.Skip(page * productsPerPage).Take(productsPerPage).ToList());
            }
        }

        public ActionResult Show(int id)
        {
            ProductDetailsModel productModel = new ProductDetailsModel();
            using (var entities = new AlmaDBEntities())
            {   
                var product = (from p in entities.Products where p.ID == id select p).First();
                productModel.ID = product.ID;
                productModel.ID_Section = product.ID_Section;

                var section = (from p in entities.Sections where p.ID == productModel.ID_Section select p).First();
                productModel.Name_Section = section.Name;

                var cat = (from p in entities.Categories where p.ID == section.ID_Category select p).First();
                productModel.ID_Cat = cat.ID;
                productModel.Name_Cat = cat.Name;

                var shop = (from p in entities.Shops where p.ID == product.ID_Shop select p).First();
                productModel.Name_Shop = shop.Name;
                productModel.ID_Shop = product.ID_Shop;

                var pr = product.Prices.OrderByDescending(x => x.Date).FirstOrDefault();
                if (pr != null)
                    productModel.Price = pr.Value;
                productModel.PriceCriterion = product.PriceCriterion;

                productModel.Availability = product.Availability;

                productModel.Name = product.Name;
                productModel.Description = product.Description;
                productModel.ImgUrl = product.ImgUrl ?? "~/Content/images/unavailable.gif";
                productModel.CriterionList = new List<Tuple<string, string, string, long>>();
                foreach (var criterion in (from jtable in entities.ProductCriterions
                        join criteria in entities.Criteria on jtable.ID_Criterion equals criteria.ID
                            into ords
                        where jtable.ID_Product == id
                        select jtable))
                {
                    productModel.CriterionList.Add(Tuple.Create(criterion.Criterion.Name, criterion.Value, criterion.Criterion.Unit, criterion.Criterion.ID));
                }
                productModel.reviews = new List<ProductReviewModel>();
                var comments = from reviewz in entities.T_Product_Reviews
                               where reviewz.ID_Product == productModel.ID
                               select reviewz;
                int count = 0;
                int? totalScore = 0;
                foreach (var review in comments)
                {
                    ProductReviewModel model = new ProductReviewModel();
                    model.Text = review.Text;
                    var usr = from users in entities.Users
                              where review.ID_User == users.ID
                              select users;
                    model.Name_User = usr.First().Firstname;
                    model.Date = review.Date;
                    if (review.Score != null)
                    {
                        count++;
                        totalScore += review.Score;
                    }
                    if (count != 0)
                        productModel.score = (float)totalScore / (float)count;
                    else
                        productModel.score = 0;
                    productModel.reviews.Add(model);
                }
                productModel.reviews.Reverse();


                productModel.Lists = new List<ListModel>();

                var lists = from ulists in entities.T_List
                            where ulists.J_List_Products.Any(x => x.ID_Product == id)
                            select ulists;

                foreach (var u in lists)
                    productModel.Lists.Add(new ListModel(u.ID_List, u.ID_User,u.List_Name));

                //
                // Similar products stuff
                //

                var refID = product.ID;

                // First, update the graph

                if (Session["PrevProduct"] != null)
                {
                    var targetID = (long)Session["PrevProduct"];
                    if (targetID != refID)
                    {

                        var localLink =
                            entities.SimilarProducts.Where(
                                x => (x.LeftProduct.ID == refID && x.RightProduct.ID == targetID) ||
                                     (x.RightProduct.ID == refID && x.LeftProduct.ID == targetID)).SingleOrDefault();

                        if (localLink == null)
                        {
                            localLink = new SimilarProduct();
                            localLink.ID_LeftProduct = refID;
                            localLink.ID_RightProduct = targetID;
                            localLink.Weight = 1;
                            entities.SimilarProducts.AddObject(localLink);
                            entities.SaveChanges();
                        }
                        else
                        {
                            localLink.Weight += 1;
                            entities.SaveChanges();
                        }
                    }
                }
                Session["PrevProduct"] = product.ID;

                // Second, identify similars for the current product
                const int MaxSimilars = 8;

                productModel.Similars = new List<Product>();
                var sims = entities.SimilarProducts.Where(x => x.LeftProduct.ID == refID || x.RightProduct.ID == refID)
                    .OrderByDescending(x => x.Weight)
                    .Take(MaxSimilars);

                foreach (var sim in sims)
                {
                    productModel.Similars.Add(sim.LeftProduct == product ? sim.RightProduct : sim.LeftProduct);
                }

                var simsToAdd = new List<Product>();
                foreach (var target in productModel.Similars)
                {
                    if (productModel.Similars.Count + simsToAdd.Count >= MaxSimilars)
                        break;

                    var targetID = target.ID;
                    var sims2 =
                        entities.SimilarProducts.Where(x => x.LeftProduct.ID == targetID || x.RightProduct.ID == targetID)
                            .OrderByDescending(x => x.Weight)
                            .Take(MaxSimilars);

                    foreach (var sim in sims2)
                    {
                        if (productModel.Similars.Count + simsToAdd.Count >= MaxSimilars)
                            break;

                        var newProd = sim.LeftProduct.ID == targetID ? sim.RightProduct : sim.LeftProduct;
                        if (newProd != product && !simsToAdd.Contains(newProd) && !productModel.Similars.Contains(newProd))
                            simsToAdd.Add(newProd);
                    }
                }
                productModel.Similars.AddRange(simsToAdd);


            }

            List<int> list = new List<int>();
            for (int i = 1; i < 6; i++)
                list.Add(i);
            ViewData["drop"] = new SelectList(list);
            return View(productModel);
        }

        public ActionResult Create(int id)
        {
            List<string> list = new List<string>();
            //List<string> list2 = new List<string>();
            using (var context = new AlmaDBEntities())
            {
                var sect = from sections in context.Sections select sections;
                list.AddRange (sect.Select (c => c.Name));
                //var shop = from shops in context.Shops select shops;
                //list2.AddRange (shop.Select (c => c.Name));
            }
            ViewData["drop_section"] = new SelectList(list);
            //ViewData["drop_shop"] = new SelectList(list2);
            return View (new ProductDetailsModel {ID_Shop = id});
        }

        [HttpPost]
        public ActionResult Create(ProductDetailsModel newProd)
        {
            if (!ModelState.IsValid)
            {
                return View(newProd);
            }
            using (var context = new AlmaDBEntities())
            {
                Product product = new Product
                                      {
                                          Name = newProd.Name,
                                          Description = newProd.Description,
                                          ImgUrl = newProd.ImgUrl
                                      };
                var section = from sections in context.Sections
                          where sections.Name == newProd.Name_Section
                          select sections;
                product.ID_Section = section.First().ID;
                //var shop = from shops in context.Shops
                //          where shops.Name == newProd.Name_Shop
                //          select shops;
                product.ID_Shop = newProd.ID_Shop;
                product.Availability = 1;
                context.Products.AddObject(product);
                context.SaveChanges();
            }
          //  return RedirectToAction ("IndexByShopId", new {shopId = newProd.ID_Shop});
            return RedirectToAction("Edit", "Shop", new { id = newProd.ID_Shop });
        }

        public ActionResult Edit(int id)
        {
            using (var entities = new AlmaDBEntities())
            {
                var product = (from p in entities.Products where p.ID == id select p).First();
                product.ImgUrl = product.ImgUrl ?? "~/Content/images/unavailable.gif";
                List<string> list = new List<string>();
                List<string> list2 = new List<string>();
                list2.Add("En stock");
                list2.Add("Temporairement épuisé");
                list2.Add("Indisponible");
                using (var context = new AlmaDBEntities())
                {
                    var sect = from sections in context.Sections select sections;
                    list.AddRange (sect.Select (c => c.Name));
                }
                ViewData["drop_section"] = new SelectList(list);
                ViewData["drop_dispo"] = new SelectList(list2);
                return View(new ProductDetailsModel(product));
            }
        }

        //
        // POST: /User/Edit/5

        [HttpPost]
        public ActionResult Edit(int id, ProductDetailsModel pro)
        {
            if (!ModelState.IsValid)
            {
                return View(pro);
            }
            using (var context = new AlmaDBEntities())
            {
                var products = from u in context.Products
                            where u.ID == id
                            select u;
                var editProduct = products.First();
                editProduct.Description = pro.Description;
                if (pro.AvailabilityName == "En stock")
                    editProduct.Availability = 1;
                else if (pro.AvailabilityName == "Temporairement épuisé")
                    editProduct.Availability = 2;
                else
                    editProduct.Availability = 0;
                /*editProduct.ID_Section = pro.ID_Section;
                editProduct.ID_Shop = pro.ID_Shop;*/
                //var sections = from u in context.Sections
                //               where u.Name == pro.Name_Section
                //               select u;
                //editProduct.ID_Section = sections.First().ID;
                //var shop = from shops in context.Shops
                //          where shops.Name == pro.Name_Shop
                //          select shops;
                //editProduct.ID_Shop = shop.First().ID;
                editProduct.Name = pro.Name;
                editProduct.ImgUrl = pro.ImgUrl;
                context.SaveChanges();
            }
            return RedirectToAction("Edit", new { id = id });
        }

        public ActionResult Delete(int id)
        {
            using (var context = new AlmaDBEntities())
            {
                var product = from products in context.Products
                              where products.ID == id
                              select products;
                return View((product.First()));
            };
        }

        //
        // POST: /Section/Delete/5

        [HttpPost]
        public ActionResult Delete(int id, Shop delProduct)
        {
            if (ModelState.IsValid)
            {
                using (var context = new AlmaDBEntities())
                {
                    var product = from products in context.Products
                                  where products.ID == id
                                  select products;
                    context.Products.DeleteObject(product.First());
                    context.SaveChanges();
                }
                //return RedirectToAction("Index");
                return RedirectToAction("Edit", "User", new { id = Session["UserId"] });
            }
            return View(delProduct);
        }

        public ActionResult Upload(ProductDetailsModel model)
        {
            var image = WebImage.GetImageFromRequest();
            var ID = 1;
            if (image != null)
            {
                if (image.Width > 500)
                {
                    image.Resize(500, ((500 * image.Height) / image.Width));
                }

                var filename = Path.GetFileName(image.FileName);
                image.Save(Path.Combine("../Content/images/products", filename));
                filename = Path.Combine("~/Content/images/products", filename);
                model.ImgUrl = Url.Content(filename);
               using (var entities = new AlmaDBEntities())
                {
                    var product = (from p in entities.Products where p.ID == ID select p).First();
                    if (product != null)
                    {
                        product.ImgUrl = model.ImgUrl;
                        entities.SaveChanges();
                    }
                }
              
            }
            return View(model);
        }

        public ActionResult AddReview(ProductDetailsModel p)
        {
            using (var context = new AlmaDBEntities())
            {
                T_Product_Reviews rev = new T_Product_Reviews();
                rev.Text = p.reviewText;
                try
                {
                    rev.ID_User = (long)Session["UserId"];
                }
                catch (Exception)
                {
                    return RedirectToAction("Connect", "User");
                }
                rev.ID_Product = p.ID;
                rev.Date = DateTime.Now;
                if (p.reviewScore < 1)
                    p.reviewScore = 1;
                else if (p.reviewScore > 5)
                    p.reviewScore = 5;
                rev.Score = p.reviewScore;
                context.T_Product_Reviews.AddObject(rev);
                context.SaveChanges();
            }
            return RedirectToAction("Show", new { id = p.ID });
        }
    }

}
